import ij.ImagePlus;
import ij.plugin.PlugIn;
import ij.process.ColorProcessor;
import ij.process.ImageProcessor;


import java.awt.Color;


import java.awt.Font;

import java.awt.Polygon;
import java.io.PrintStream;

import java.util.Locale;
import java.util.Random; 



import pluginUtils.Circle;
import pluginUtils.CircleArrangement;
import pluginUtils.Complexe; 
import pluginUtils.DoyleCircle;
import pluginUtils.MobiusTransform;
import pluginUtils.CircleInversion;
import pluginUtils.PackCircle;
import pluginUtils.Point2D;
import pluginUtils.Pos3D;
import pluginUtils.Sphere;
import pluginUtils.SphereInversion;

// La version actuelle est #454

public class KochForAnamorphosis extends ImagePlus implements PlugIn{
	{Locale.setDefault(Locale.US); }
	
	private ImageProcessor primeIP; 
	private int X=2000,Y=2000; // image size
	
	private PrintStream output;
	private double xShift=0; 
	private double zShift=0; 
	
	

	private Random generator=new Random(); // One always needs some randomness
	
	// For the scaling of the image
	private double x0=0,x1=1,y0=0,y1=1;
	private double acoef,ccoef,vcoef,wcoef; 
	
	private String[] palette={"Yellow","Red","Blue","Green","White","NavyBlue","Turquoise","Orange"};
	private Color[] palette1={Color.YELLOW,Color.RED,Color.BLUE,Color.GREEN,Color.MAGENTA,Color.ORANGE};
	public void setCoefs(){
		acoef=X/(x1-x0); 
		vcoef=Y/(y1-y0); 
		ccoef=-acoef*x0; 
		wcoef=-vcoef*y0; 
	}
	 
	
	
	public void setBounds(double xl,double xu,double yl,double yu){
		x0=xl; 
		x1=xu;
		y0=yl;
		y1=yu; 
	}
	
	private void drawCircle(Point2D C,double r){
		double xCenter=C.getX(); 
		double yCenter=C.getY(); 
		
		primeIP.setColor(Color.BLUE); 
		//drawPoint(xCenter,-yCenter);
		primeIP.setColor(Color.BLACK);
		
		int intX=(int)((xCenter)*acoef+ccoef);
		int intY=(int)((yCenter)*vcoef+wcoef);
		int intRx=(int)(r*acoef);
		int intRy=(int)(r*vcoef);
		
		
		primeIP.drawOval(intX-intRx,intY-intRy,intRx*2,intRy*2);
	}
	
	private void drawPoint(double x,double y){
		int radi=15; 
		int intX=(int)(x*acoef+ccoef);
		int intY=(int)(y*vcoef+wcoef);
		primeIP.fillOval(intX-radi,intY-radi,2*radi,2*radi);
	}
	
	private void drawPoint(Point2D p){
		int intX=(int)(p.getX()*acoef+ccoef);
		int intY=(int)(p.getY()*vcoef+wcoef);
		primeIP.fillOval(intX-10,intY-10,20,20);
	}
	
	
	
	
	private void drawLine(double xd,double yd,double xf,double yf){
		int XD=(int)(xd*acoef+ccoef); 
		int YD=(int)(yd*vcoef+wcoef); 
		int XF=(int)(xf*acoef+ccoef); 
		int YF=(int)(yf*vcoef+wcoef);
		primeIP.drawLine(XD,YD,XF,YF); 
	}
	
	
	private void drawLine(Point2D p,Point2D q){
		int XD=(int)(p.getX()*acoef+ccoef); 
		int YD=(int)(p.getY()*vcoef+wcoef); 
		int XF=(int)(q.getX()*acoef+ccoef); 
		int YF=(int)(q.getY()*vcoef+wcoef);
		String s="traceLigne(<0,"+p.getX()+","+p.getY()+">*imax,<0,"+q.getX()+","+q.getY()+">*imax,indmax,0)"; 
		System.out.println(s);
		primeIP.drawLine(XD,YD,XF,YF); 
	}
	
	/*
	#macro kochCord(a,b,n,p,ia)
	# local c=vrotate((b-a)/3,<0,0,60>);
	#if (n>0)

	kochCord(a,a+(b-a)/3,n-1,p/4,ia) 
	kochCord(a+(b-a)/3,a+(b-a)/3+c,n-1,p/4,ia+p)
	kochCord( a+(b-a)/3+c,a+2*(b-a)/3,n-1,p/4,ia+2*p)
	kochCord(a+2*(b-a)/3,b,n-1,p/4,ia+3*p)

	#else
	afficheVecteur(a,ia)
	afficheVecteur(a+(b-a)/3,ia+p)
	afficheVecteur(a+(b-a)/3+c,ia+2*p)
	afficheVecteur(a+2*(b-a)/3,ia+3*p)
	afficheVecteur(b,ia+4*p)
	#end
	#end

	#declare AA=<0,0,0>;
	#declare BB=<1,0,0>;  
	kochCord(AA,BB,6,1/4,0)
*/
		void koch(Point2D A,Point2D B,int level,double dx,double dy,double rot){
			Point2D c=Point2D.mul(Point2D.sub(B, A),1/3.0); // (b-a)/3
			Point2D auxi1=Point2D.add(A,c); // a+(b-a)/3
			
			Point2D auxi3=Point2D.add(auxi1,c); // a+2*(b-a)/3
			
			double cx=c.getX(); 
			double cy=c.getY(); 
			c.setX(cx*Math.cos(Math.PI/3)+cy*Math.sin(Math.PI/3)); 
			c.setY(-cx*Math.sin(Math.PI/3)+cy*Math.cos(Math.PI/3)); 
			Point2D auxi2=Point2D.add(auxi1,c); // a+(b-a)/3+c
			if(level>0){
				koch(A,auxi1,level-1,dx,dy,rot); 
				koch(auxi1,auxi2,level-1,dx,dy,rot); 
				koch(auxi2,auxi3,level-1,dx,dy,rot);
				koch(auxi3,B,level-1,dx,dy,rot); 
			}
			else{
				Point2D decal=new Point2D(dx,dy); 
				drawLine(Point2D.rotate(Point2D.add(A,decal),rot),Point2D.rotate(Point2D.add(B,decal),rot));
				/*
				drawLine(Point2D.rotate(Point2D.add(A,decal),rot),Point2D.rotate(Point2D.add(auxi1,decal),rot));
				drawLine(Point2D.rotate(Point2D.add(auxi1,decal),rot),Point2D.rotate(Point2D.add(auxi2,decal),rot));
				drawLine(Point2D.rotate(Point2D.add(auxi2,decal),rot),Point2D.rotate(Point2D.add(auxi3,decal),rot));
				drawLine(Point2D.rotate(Point2D.add(auxi3,decal),rot),Point2D.rotate(Point2D.add(B,decal),rot));
				*/
			}
			
		}
	
	public void run(String arg) {
		primeIP = new ColorProcessor(X,Y);
	
		double limit=1.2; //0.355; //0.5;  //0.355
		double lmoins=-1.2; //0.352; //0.352 pour lev>=5
		//setBounds(0.30504,0.30504+0.0498,-0.41256+0.02,-0.41256+0.0498+0.02); 
		setBounds(lmoins,limit,lmoins,limit);
		setCoefs(); 
		
		Polygon background=new Polygon(new int[]{0,0,X,Y},new int[]{0,X,Y,0},4);
		primeIP.setColor(Color.WHITE);
		
		primeIP.fillPolygon(background);
		
		
		primeIP.setFont(new Font(null,Font.ITALIC,60));
		primeIP.setColor(Color.BLACK);
		
		setProcessor("Verifying", primeIP);
		
		primeIP.setLineWidth(3);
		int lev=4; 
		Point2D AA=new Point2D(0,0);
		Point2D BB=new Point2D(1,0);
		koch(AA,BB,lev,-0.5,-Math.sqrt(3)/6,0); 
		koch(AA,BB,lev,-0.5,-Math.sqrt(3)/6,-2*Math.PI/3); 
		koch(AA,BB,lev,-0.5,-Math.sqrt(3)/6,2*Math.PI/3); 
		/*
		primeIP.setColor(Color.RED);
		koch(AA,BB,lev,-0.5,-Math.sqrt(3)/6,Math.PI/2); 
		koch(AA,BB,lev,-0.5,-Math.sqrt(3)/6,-2*Math.PI/3+Math.PI/2); 
		koch(AA,BB,lev,-0.5,-Math.sqrt(3)/6,2*Math.PI/3+Math.PI/2);
		*/ 
		/*
		primeIP.setColor(Color.GREEN);
		koch(AA,BB,lev-1,-0.5,-Math.sqrt(3)/6,Math.PI/2); 
		koch(AA,BB,lev-1,-0.5,-Math.sqrt(3)/6,-2*Math.PI/3+Math.PI/2); 
		koch(AA,BB,lev-1,-0.5,-Math.sqrt(3)/6,2*Math.PI/3+Math.PI/2); 
		*/
		/*
		drawPoint(new Point2D(0,0)); 
		drawLine(x1,y1,x0,y0); 
		drawLine(x1,y0,x0,y1); 
		*/
		//drawPoint(new Point2D(0.352,0.352)); 
		/*
		drawLine(0.3,0.3,0.4,0.3); 
		drawLine(0.3,0.3,0.3,0.4); 
		drawLine(0.4,0.4,0.4,0.3); 
		drawLine(0.4,0.4,0.3,0.4); 
		*/
		
		primeIP.setColor(Color.BLACK); 
		drawLine(0,y0,0,y1); 
		drawLine(x0,0,x1,0); 
		
		show();
	}	
}
